<?php
/**
 * Created by PhpStorm.
 * User: peter
 * Date: 2018/11/2
 * Time: 12:57 PM
 */

namespace app\admin\logic;


use app\model\AccountCapitalFlow;
use app\model\ActivityOrderAttach;
use app\model\Bill;
use extend\Functions;
use extend\STATUS_CODE;
use Naixiaoxin\ThinkWechat\Facade;
use think\facade\Env;

class ActivityOrderRefund
{
    /**
     * @purpose 拒绝退款
     * @param int $refund_id
     * @param string $reason
     * @param int $administrator_id
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @throws \think\exception\PDOException
     */
    public static function refuse (int $refund_id, string $reason, int $administrator_id): array
    {
        if (!$reason) {
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                '缺少拒绝原因...!'
            );
        }
        $order      = new \app\model\ActivityOrder();
        $order_refund = new \app\model\ActivityOrderRefund();
        $order_attach = new ActivityOrderAttach();
        $order_refund->startTrans();
        $order_refund_info = $order_refund
            ->lock(true)
            ->alias('or')
            ->join('activity_order ao', 'or.order_id=ao.id')
            ->where('or.id', $refund_id)
            ->field('or.id,or.order_id,or.order_attach_id,or.status,ao.status as  order_status')
            ->find();
        if (!$order_refund_info) {
            return Functions::result(
                STATUS_CODE::FAIL,
                '退款订单不存在...!'
            );
        }
        if ($order_refund_info->status !== 1) {
            return Functions::result(
                STATUS_CODE::FAIL,
                '当前状态不可对该退款订单进行拒绝操作...!'
            );
        }
        $order_refund_result  = $order_refund
            ->isUpdate(true)
            ->save(
                ['status' => 4, 'refuse_reason' => $reason, 'administrator_id' => $administrator_id],
                ['id' => $order_refund_info->id]
            );
        $order_attach_result  = $order_attach
            ->where('id', 'in', $order_refund_info->order_attach_id)
            ->update(['status' => 99]);
        $order_result = true;
        // 恢复订单状态
        if ($order_refund_info->order_status !== 99) {
            $order_result = $order
                ->isUpdate(true)
                ->save(['status' => 99], ['id' => $order_refund_info->order_id]);
        }
        if ($order_refund_result && $order_attach_result && $order_result) {
            $order_refund->commit();
            return Functions::result();
        }
        $order_refund->rollback();
        return Functions::result(
            STATUS_CODE::UPDATE_FAIL,
            '拒绝失败...!'
        );
    }

    /**
     * @purpose 同意退款
     * @param int $refund_id
     * @param int $administrator_id
     * @return array
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @throws \think\exception\PDOException
     * @throws \Exception
     */
    public static function agree (int $refund_id, int $administrator_id): array
    {
        $order_refund       = new \app\model\ActivityOrderRefund();
        $order              = new \app\model\ActivityOrder();
        $order_attach       = new ActivityOrderAttach();
        $member             = new \app\model\Member();
        $order_refund->startTrans();
        $order_refund_info = $order_refund
            ->with(['activity' => function($query) {
                $query->field('id,title');
            }])
            ->lock(true)
            ->where('id', $refund_id)
            ->field('id,pay_no,uid,activity_id,order_id,order_no,order_attach_id,pay_method,pay_money,refund_money,refund_no,status,refund_reason')
            ->find();
        if (!$order_refund_info) {
            $order_refund->rollback();
            return Functions::result(
                STATUS_CODE::FAIL,
                '退款订单不存在'
            );
        }
        if ($order_refund_info->status !== 1) {
            $order_refund->rollback();
            return Functions::result(
                STATUS_CODE::FAIL,
                '当前订单状态不可进行退款操作!'
            );
        }
        $refund = [];
        $member_result = true;
        $refund['refund_id'] = '';
        switch ($order_refund_info->pay_method) {
            case 1: // 微信支付
                $refund              = self::wechatOfficialAccountRefund(
                    $order_refund_info->pay_no,
                    $order_refund_info->refund_no,
                    $order_refund_info->pay_money,
                    $order_refund_info->refund_money,
                    $order_refund_info->refund_reason
                );
                break;
            case 2: // 微信小程序支付
                break;
            case 3: // 支付宝支付
                $refund     = self::alipayRefund(
                    $order_refund_info->order_no,
                    $order_refund_info->pay_no,
                    $order_refund_info->refund_money / 100,
                    $order_refund_info->refund_reason,
                    $order_refund_info->refund_no
                );
                break;
            case 10: // 余额支付
                $member_result = $member
                    ->where('uid', $order_refund_info->uid)
                    ->setInc('balance', $order_refund_info->refund_money);
                AccountCapitalFlow::M()
                    ->data([
                        'uid'          => $order_refund_info->uid,
                        'quota'        => $order_refund_info->refund_money,
                        'type'         => 1,
                        'descriptions' => '退款原因【'.$order_refund_info->refund_reason.'】',
                    ])
                    ->save();
                break;
        }
        $status = 5;
        if (in_array($order_refund_info->pay_method, [3, 10])) {
            $status = 3;
        }
        $refund_result       = $order_attach
            ->isUpdate(true)
            ->save(
                ['status' => $status],
                [['id', 'in', $order_refund_info->order_attach_id]]
            );

        $order_result = true;

        $status = 2;
        if (in_array($order_refund_info->pay_method, [3, 10])) {
            $status = 3;
        }
        $refund_order_result = $order_refund
            ->isUpdate(true)
            ->save(
                [
                    'status'         => $status,
                    'transaction_id' => $refund['refund_id'],
                    'administrator_id' => $administrator_id
                ],
                ['id' => $refund_id]
            );
        // 检测当前订单是否全部申请退款，若全部退款则修改订单状态
        $whereStr = 'order_id='.$order_refund_info->order_id.' and `status` in(4,5,99) and `id` not in('.$order_refund_info->order_attach_id.')';
        if ($order_attach->where($whereStr)->count(1) < 1) {
            $status = 5;
            if (in_array($order_refund_info->pay_method, [3, 10])) {
                $status = 3;
            }
            $order_result = $order
                ->isUpdate(true)
                ->save(['status' => $status], ['id' => $order_refund_info->order_id]);
        }
        // 记录账单活动支付账单
        Bill::addToBill(
            $order_refund_info->uid,
            2,
            $order_refund_info->refund_no,
            $order_refund_info->refund_money,
            0,
            '活动退款: 【'.$order_refund_info->activity->title.'】,退款原因【'.$order_refund_info->refund_reason.'】'
        );
        if ($refund_result &&
            $order_result &&
            $member_result &&
            $refund_order_result) {
            $order_refund->commit();
            return Functions::result();
        }
        $order_refund->rollback();
        return Functions::result(
            STATUS_CODE::FAIL,
            '操作失败'
        );

    }
    /**
     * @purpose 支付宝退款
     * @param $out_trade_no // 订单支付时传入的商户订单号,不能和 trade_no同时为空。
     * @param $trade_no // 支付宝交易号，和商户订单号不能同时为空
     * @param $refund_amount // 需要退款的金额，该金额不能大于订单金额,单位为元，支持两位小数
     * @param $refund_reason // 退款的原因说明
     * @param $out_request_no // 标识一次退款请求，同一笔交易多次退款需要保证唯一，如需部分退款，则此参数必传。
     * @throws \Exception
     */
    private static function alipayRefund (
        $out_trade_no,
        $trade_no,
        $refund_amount,
        $refund_reason,
        $out_request_no) {
        include Env::get('root_path'). 'extend/alipay/AopSdk.php';
        include Env::get('root_path'). 'extend/alipay/aop/request/AlipayTradeRefundRequest.php';
        $aop = new \AopClient();
        $aop->gatewayUrl                = 'https://openapi.alipay.com/gateway.do';
        $aop->appId                     = config('alipay.app.appid');
        $aop->rsaPrivateKey             = config('alipay.app.private_key');
        $aop->format                    = "json";
        $aop->charset                   = "UTF-8";
        $aop->signType                  = "RSA";
        $aop->apiVersion                = '1.0';
        $aop->alipayrsaPublicKey        = config('alipay.app.public_key');
        $content = [];
        $content['out_trade_no']        = $out_trade_no;
        $content['trade_no']            = $trade_no;
        $content['refund_amount']       = $refund_amount;
        $content['refund_reason']       = $refund_reason;
        $content['out_request_no']      = $out_request_no;
        $request = new \AlipayTradeRefundRequest();
        $request->setBizContent(json_encode($content));
        $result = $aop->execute($request);
        $responseNode = str_replace(".", "_", $request->getApiMethodName()) . "_response";
        if ((int) $result->$responseNode->code !== 10000) {
            exception($result->$responseNode->msg);
        }
        return ['refund_id' => $result->$responseNode->trade_no];
    }
    /**
     * @purpose 微信公众号退款
     * @param $transaction_id 微信支付单号
     * @param $refund_no 退款单号
     * @param $total_money 订单总金额
     * @param $refund_money 退款金额
     * @param string $total_money 退款原因
     * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     */
    private static function wechatOfficialAccountRefund(
        $pay_no,
        $refund_no,
        $total_money,
        $refund_money,
        $reason = '')
    {
        $app    = Facade::payment('official_account');
        $result = $app->refund->byTransactionId(
            $pay_no,
            $refund_no,
            $total_money,
            $refund_money,
            [
                'refund_desc' => $reason,
                'notify_url'  => config('wechat.payment.official_account.refund_notify_url'),
            ]
        );
        // 申请退款成功
        if (isset($result['result_code']) && $result['result_code'] === 'SUCCESS') {
            return $result;
        }
        if (isset($result['err_code_des'])) {
            exception($result['err_code_des']);
        }
        exception($result['return_msg']);

    }
    /**
     * @purpose 获取取消订单中的出现人
     * @param int $refund_id
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public static function cancelTravelItems (int $refund_id): array
    {
        $order_refund      = new \app\model\ActivityOrderRefund();
        $order_attach      = new ActivityOrderAttach();
        $attach_ids        = $order_refund
            ->where('id', $refund_id)
            ->value('order_attach_id');
//        return [$attach_ids];
        if (!$attach_ids) {
            return Functions::result();
        }
        $list  = $order_attach
            ->with(['activityCollectionPoint' => function($query) {
                $query->field('id,title,address');
            }])
            ->where('id', 'in', $attach_ids)
            ->field('id,order_id,activity_id,group_stage_id,collection_point_id,fullname,
            travel_type,travel_sex,travel_mobile,travel_certificate_type,travel_certificate_number,
            price,status,cancel_reason')
            ->select();
        return Functions::result($list);
    }
    /**
     * @purpose 获取退款订单列表
     * @param int $status
     * @param int $page
     * @param int $size
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public static function items (int $status = 1, $page = 1, $size = 20): array
    {
        $order_refund = new \app\model\ActivityOrderRefund();
        $total        = $order_refund
            ->where('status', $status)
            ->count(1);
        $list       = $order_refund
            ->where('status', $status)
            ->with(['member' => function($query) {
                $query->field('uid,username,nickname,mobile');
            }, 'administrator' => function($query) {
                $query->field('uid,name');
            }])
            ->field('id,order_id,uid,administrator_id,activity_id,group_stage_id,order_no,
            pay_no,pay_voucher,pay_method,pay_money,refund_no,status,refund_reason,
            refuse_reason,refund_money,FROM_UNIXTIME(create_at, "%Y-%m-%d %H:%i:%s") as apply_date')
            ->page($page, $size)
            ->order('create_at desc')
            ->select();
//        dump($list);
//        exit;
//        $_list = $list->toArray();
//        foreach ($_list as &$item) {
//            if (is_null($item['member']['username'])) {
//                $item['member']['username'] = '';
//            }
//            if (is_null($item['member']['nickname'])) {
//                $item['member']['nickname'] = '';
//            }
//            if (is_null($item['member']['mobile'])) {
//                $item['member']['mobile'] = '';
//            }
//        }
        return Functions::result([
            'total' => $total,
            'list' => $list
        ]);
    }
}